package com.yanqu.road.server.gameplayer.module.activity.oldplayerreturn;

import com.yanqu.road.entity.activity.ActivityConditionInfo;
import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.oldplayerreturn.*;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.log.LogOldPlayerReturn;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.pb.activity.OldPlayerReturnProto;
import com.yanqu.road.pb.player.PlayerProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.activity.oldplayerreturn.OldPlayerReturnMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.pb.PlayerPb;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.server.protocol.CrossProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author ：zfr
 * @date ：2021/12/16 9:45
 */
public class OldPlayerReturnActivity {
    //活动信息
    private ActivityInfo activityInfo;

    //事件配置
    private Map<Integer, OldPlayerReturnEventConfig> eventConfigMap = new ConcurrentHashMap<>();

    private  Map<Integer,List<OldPlayerReturnDayLoginTaskConfig>>loginTaskConfigMap = new ConcurrentHashMap<>();

    private List<Integer> noNeedToAdditionTypeList = new ArrayList<>();

    //config配置项 key
    private Map<String, ActivityConfig> configMap = new ConcurrentHashMap<>();

    private static RandomHelper random = new RandomHelper();

    private int activityType = -1;

    public OldPlayerReturnActivity() {
    }

    public ActivityInfo getActivityInfo() {
        return activityInfo;
    }

    public Map<Integer, OldPlayerReturnEventConfig> getEventConfigMap() {
        return eventConfigMap;
    }

    public Map<String, ActivityConfig> getConfigMap() {
        return configMap;
    }

    public void clearActivity() {
        this.activityInfo = null;
        this.eventConfigMap = new ConcurrentHashMap<>();
        this.configMap = new ConcurrentHashMap<>();
        this.loginTaskConfigMap = new ConcurrentHashMap<>();
    }

    public void loadActivity(ActivityInfo activityInfo, Map<Integer, OldPlayerReturnEventConfig> eventConfigMap, Map<String, ActivityConfig> configMap,Map<Integer,List<OldPlayerReturnDayLoginTaskConfig>> loginTaskConfigMap,int activityType) {
        this.activityType = activityType;
        this.activityInfo = activityInfo;
        this.eventConfigMap = eventConfigMap;
        this.configMap = configMap;
        this.loginTaskConfigMap = loginTaskConfigMap;
        this.noNeedToAdditionTypeList = new ArrayList<>();
        if (configMap.containsKey("RETURN_DOUBLE_TYPE")){
            List<Integer> tmpNoNeed = configMap.get("RETURN_DOUBLE_TYPE").getIntListValue("\\|");
            this.noNeedToAdditionTypeList = tmpNoNeed;
        }
    }

    /**
     * 根据事件id获取事件配置
     * @param eventId 事件id
     * @return 对应的事件配置
     */
    public OldPlayerReturnEventConfig getEventConfig(int eventId) {
        return eventConfigMap.get(eventId); //eventId 对应的配置不存在 会返回null
    }

    /**
     * 获取key对应的配置
     * @param param 参数名
     * @return config
     */
    public ActivityConfig getActivityConfig(String param) {
        //有对活动配置做检查 应该不会返回null
        //活动过期会清空 就会返回null (可能取配置的时候活动刚好过期了)
        return configMap.get(param);
    }

    /**
     * 检查区服开服天数限制
     * @return bool
     */
    public boolean checkOpenServerDays(long registerTime) {
        ActivityConfig openLimitConfig = getActivityConfig("RETURN_OPEN_LIMIT");
        ActivityConfig effectiveTimeConfig = getActivityConfig("RETURN_EFFECTIVE_TIME");
        if (openLimitConfig == null || effectiveTimeConfig == null) {
            return false;
        }
        ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
        if (serverInfo == null) {
            return false;
        }
        //开服时间的当天0点
        long serverOpenTimeMillis = DateHelper.getZeroTimeStamp(serverInfo.getOpenTime() * DateHelper.SECOND_MILLIONS);
        long serverOpenDaysLessThan = Integer.parseInt(openLimitConfig.getValue().split("\\|")[1]) * DateHelper.DAY_MILLIONS;
        if (registerTime * 1000 <= serverOpenTimeMillis + serverOpenDaysLessThan) {
            long overTime = DateHelper.getZeroTimeStamp(registerTime * 1000) + (Integer.parseInt(effectiveTimeConfig.getValue()) * DateHelper.DAY_MILLIONS);
            return System.currentTimeMillis() < overTime;
        }
        return false;
    }

    /**
     * 检查回归持续时间
     * @param returnTime 回归时间
     * @return bool
     */
    public boolean checkReturnEffectiveTime(long returnTime) {
        ActivityConfig config = getActivityConfig("RETURN_EFFECTIVE_TIME");
        if (config == null) {
            return false;
        }
        long timeMillis = DateHelper.getTodayZeroTimeStamp() - DateHelper.getZeroTimeStamp(returnTime);
        //取的是 现在是回归的第几天 （触发回归的那天就是第一天）
        return timeMillis / DateHelper.DAY_MILLIONS + 1 <= Integer.parseInt(config.getValue());
    }

    /**
     * 获取成为回归玩家需要的离线天数
     * @return 天数
     */
    public int getNeedOfflineDays() {
        if (ActivityMgr.activityInTime(activityInfo)) {
            //配置成活动任务了 所以取活动任务配置的完成参数
            List<ActivityConditionInfo> conditionInfos = NormalActivityMgr.getActivityConditionInfoListByType(activityInfo.getActivityId(), eGamePlayerEventType.OldPlayerReturnOfflineDays.getValue());
            if (conditionInfos.size() > 0) {
                return conditionInfos.get(0).getParamList().get(3).intValue();
            }
        }
        return -1;
    }

    /**
     * 检查角色是否可以被绑定
     *
     * @param userInfo 玩家信息
     * @return bool
     */
    private CheckReturnRes checkCanBind(UserInfo userInfo) {
        CheckReturnRes res = new CheckReturnRes(false, -1);
        if (!ActivityMgr.activityInTime(activityInfo)) {
            return res;
        }
        String noTriggerActivityOldPlayerReturnTime = ChannelConfig.CAN_NO_TRIGGER_ACTIVITY_OLD_PLAYER_RETURN_TIME;
        if (!noTriggerActivityOldPlayerReturnTime.equals("0")){
            List<String> timeList = StringUtils.stringToStringList(noTriggerActivityOldPlayerReturnTime, "-");
            if (timeList.size() == 2){
                long startTime = StringUtils.string2longSafe(timeList.get(0),0);
                long endTime = StringUtils.string2longSafe(timeList.get(1),0);
                long timeMillis = System.currentTimeMillis();
                if (timeMillis >startTime&& timeMillis <= endTime){
                    return res;
                }
            }
        }
        //获取需要离线的天数
        int needOfflineDays = getNeedOfflineDays();
        if (needOfflineDays == -1) {
            return res;
        }
        long userId = userInfo.getUserId();
        //如果被封了半个月或者以上 不给绑定 【【V7.4】被封禁账号无法继承VIP - 服务端】https://www.tapd.cn/67122645/prong/tasks/view/1167122645001198139
        if (userInfo.getBlackListEndTime() > (System.currentTimeMillis() + (DateHelper.DAY_MILLIONS * 15))) {
            return res;
        }

        //获取回归数据
        OldPlayerReturnUserData returnData = OldPlayerReturnMgr.getUserData(userId);
        if (returnData == null || !returnData.isReturn()) {
            //身份等级是否足够
            ActivityConfig config = getActivityConfig("RETURN_OPEN_LIMIT");
            if (config == null) {
                return res;
            }
            if (userInfo.getTitleId() < Integer.parseInt(config.getValue().split("\\|")[0])) {
                return res;
            }
            //还没触发回归 判断一下这个角色的离线时长是不是满足
            long returnTime = userInfo.getLastLoginTime() + needOfflineDays * DateHelper.DAY_SECONDS;
            if (System.currentTimeMillis() / 1000 > returnTime) {
                res.setReturn(true);
            } else {
                res.setCanReturnTime(returnTime);
            }
            return res;
        }
        if (returnData.getNewUserId() == 0) {
            //回归了 并且还在有效时间内 并且还没绑定过的
            if (checkReturnEffectiveTime(returnData.getReturnTime()) && returnData.getActivityId() == activityInfo.getActivityId()) {
                res.setReturn(true);
            }
            return res;
        }
        return res;
    }

    /**
     * 根据openId获取回归角色的信息
     * @param openId openId
     * @return 回归角色信息列表
     */
    public GetReturnPlayerInfoRes getReturnPlayerInfo(String openId) {
        GetReturnPlayerInfoRes res = new GetReturnPlayerInfoRes();
        List<UserInfo> userInfoList = new ArrayList<>();
        long returnTime = -1;
        //有活动
        if (ActivityMgr.activityInTime(activityInfo)) {
            List<UserInfo> userInfos = UserMgr.getUserInfoByOpenId(openId);
            for (UserInfo userInfo : userInfos) {
                //可以绑定的才返回
                CheckReturnRes checkReturnRes = checkCanBind(userInfo);
                if (checkReturnRes.isReturn()) {
                    userInfoList.add(userInfo);
                } else {
                    if (returnTime == -1 || returnTime > checkReturnRes.getCanReturnTime()) {
                        returnTime = checkReturnRes.getCanReturnTime();
                    }
                }
            }
        }
        res.setUserInfoList(userInfoList);
        res.setReturnTime(returnTime);
        return res;
    }

    /**
     * 跨服来绑定
     *
     * @param playerId    绑定的玩家id
     * @param oriServerId 发起的区服id
     * @param oriUserId   发起的玩家id
     * @param oriOpenId   发起的玩家openId
     * @param oriUserInfo 发起的玩家信息
     * @return ret
     */
    public  int crossBindPlayer(long playerId, long oriServerId, long oriUserId, String oriOpenId, PlayerProto.PlayerBaseTempMsg oriUserInfo) {
        if (!ActivityMgr.activityInTime(activityInfo)) {
            return GameErrorCode.E_ACTIVITY_NO_FOUND;
        }
        UserInfo userInfo = UserMgr.getUserInfo(playerId);
        if (userInfo == null) {
            return GameErrorCode.E_PLAYER_RETURN_BIND_ROLE_USER_NO_FOUND;
        }
        //openId 对不上
        if (!userInfo.getOpenId().equals(oriOpenId)) {
            return GameErrorCode.E_PLAYER_RETURN_BIND_ROLE_NOT_BELONG_PLAYER;
        }
        //玩家是不是符合回归 可以被绑定
        if (!checkCanBind(userInfo).isReturn()) {
            return GameErrorCode.E_PLAYER_RETURN_BIND_ROLE_CANT_BIND;
        }
        String noTriggerActivityOldPlayerReturnTime = ChannelConfig.CAN_NO_TRIGGER_ACTIVITY_OLD_PLAYER_RETURN_TIME;
        if (!noTriggerActivityOldPlayerReturnTime.equals("0")){
            List<String> timeList = StringUtils.stringToStringList(noTriggerActivityOldPlayerReturnTime, "-");
            if (timeList.size() == 2){
                long startTime = StringUtils.string2longSafe(timeList.get(0),0);
                long endTime = StringUtils.string2longSafe(timeList.get(1),0);
                long timeMillis = System.currentTimeMillis();
                if (timeMillis >startTime&& timeMillis <= endTime){
                    return GameErrorCode.E_PLAYER_RETURN_NOT_RETURN_ROLE;
                }
            }
        }
        //可以 就先回归玩家
        OldPlayerReturnMgr.userReturn(playerId, activityInfo.getActivityId(), activityInfo.getType(), System.currentTimeMillis());
        OldPlayerReturnUserData data = OldPlayerReturnMgr.getUserData(playerId);
        //再记录一下被谁绑定的
        if (data != null) {
            data.setNewUserId(oriUserId);
            data.setNewServerId(oriServerId);
            data.setNewTime(System.currentTimeMillis());
            data.setNewUserBaseInfo(PlayerBasePb.parseToUserBaseInfo(oriUserInfo));

            try {
                AutoLogMgr.add(new LogOldPlayerReturn(
                        playerId,
                        activityInfo.getActivityId(),
                        new Date(data.getReturnTime()),
                        new Date(Objects.requireNonNull(UserMgr.getUserInfo(playerId)).getLastLoginTime() * DateHelper.SECOND_MILLIONS),
                        true,
                        oriUserId,
                        new Date(System.currentTimeMillis())
                ));
            } catch (Exception e) {
                OldPlayerReturnMgr.getLogger().error(e);
            }
        }
        //返回区服告诉结果
        OldPlayerReturnProto.BindReturnRoleSuccessRespCrossMsg.Builder reqMsg = OldPlayerReturnProto.BindReturnRoleSuccessRespCrossMsg.newBuilder();
        reqMsg.setRet(0);
        reqMsg.setOriServerId(oriServerId);
        reqMsg.setOriUserId(oriUserId);
        reqMsg.setVipExp(userInfo.getVipExp());
        reqMsg.setBindUserInfo(PlayerPb.parsePlayerBaseTempMsg(userInfo));
        YanQuMessage message = YanQuMessageUtils.buildMessage(CrossProtocol.C_CROSS_BIND_RETURN_ROLE_SUCCESS_RESP, reqMsg);
        GamePlayerMgr.sendPacket(playerId, message);

        //在线 同步下消息
        GamePlayer player = GamePlayerMgr.getOnlinePlayer(playerId);
        if (player != null) {
            player.getModule(OldPlayerReturnModule.class).syncReturnPlayerData();
        }
        return 0;
    }

    /**
     * 随机事件
     * @return eventConfig
     */
    public OldPlayerReturnEventConfig randomEvent() {
        List<OldPlayerReturnEventConfig> eventConfigList = new ArrayList<>(getEventConfigMap().values());
        List<Integer> weightList = eventConfigList.stream().map(OldPlayerReturnEventConfig::getWeight).collect(Collectors.toList());
        int allWeight = weightList.stream().mapToInt(Integer::intValue).sum();
        int randomNum = random.next(allWeight) + 1;
        int nowWeight = 0;
        int index = -1;
        for (int i = 0; i < weightList.size(); i++) {
            nowWeight += weightList.get(i);
            if (nowWeight >= randomNum) {
                index = i;
                break;
            }
        }
        return eventConfigList.get(index);
    }

    public Map<Integer, List<OldPlayerReturnDayLoginTaskConfig>> getLoginTaskConfigMap() {
        return loginTaskConfigMap;
    }

    public void setLoginTaskConfigMap(Map<Integer, List<OldPlayerReturnDayLoginTaskConfig>> loginTaskConfigMap) {
        this.loginTaskConfigMap = loginTaskConfigMap;
    }

    public boolean chickRewardNeedAddition(int conditionType){
        return !noNeedToAdditionTypeList.contains(conditionType);
    }

    public int getActivityType() {
        return activityType;
    }
}
